<template>
    <Mapbox :mapOnLoadCB="mapOnLoadCB"></Mapbox>
</template>

<script>
import {ref} from "vue"
import Mapbox from "@/components/common/Mapbox.component.vue"
import MapboxCommonService from "@/service/map/MapboxCommonService"

export default {
    name: "AddHTMLCluster.component",
    components: {Mapbox},
    setup() {

        let mapStore = ref({});
        let mapOnLoadCB = (map) => {
            mapStore.value = map;
            MapboxCommonService.setCZBP(map, [0, 20], 0.3)

            map.addControl(new mapboxgl.NavigationControl());

            // code for creating an SVG donut chart from feature properties
            const createDonutChart = (props) => {
                let offsets = [];
                let counts = [props.mag1, props.mag2, props.mag3, props.mag4, props.mag5];
                let total = 0;
                for (let i = 0; i < counts.length; i++) {
                    offsets.push(total);
                    total += counts[i];
                }
                let fontSize = total >= 1000 ? 22 : total >= 100 ? 20 : total >= 10 ? 18 : 16;
                let r = total >= 1000 ? 50 : total >= 100 ? 32 : total >= 10 ? 24 : 18;
                let r0 = Math.round(r * 0.6);
                let w = r * 2;

                let html = '<svg width="' + w + '" height="' + w + '" viewbox="0 0 ' + w + ' ' + w +
                    '" text-anchor="middle" style="font: ' + fontSize + 'px sans-serif">';

                for (let i = 0; i < counts.length; i++) {
                    html += donutSegment(offsets[i] / total, (offsets[i] + counts[i]) / total, r, r0, colors[i]);
                }
                html += '<circle cx="' + r + '" cy="' + r + '" r="' + r0 +
                    '" fill="white" /><text dominant-baseline="central" transform="translate(' +
                    r + ', ' + r + ')">' + total.toLocaleString() + '</text></svg>';

                let el = document.createElement('div');
                el.innerHTML = html;
                return el.firstChild;
            }

            const donutSegment = (start, end, r, r0, color) => {
                if (end - start === 1) end -= 0.00001;
                let a0 = 2 * Math.PI * (start - 0.25);
                let a1 = 2 * Math.PI * (end - 0.25);
                let x0 = Math.cos(a0), y0 = Math.sin(a0);
                let x1 = Math.cos(a1), y1 = Math.sin(a1);
                let largeArc = end - start > 0.5 ? 1 : 0;

                return ['<path d="M', r + r0 * x0, r + r0 * y0, 'L', r + r * x0, r + r * y0,
                    'A', r, r, 0, largeArc, 1, r + r * x1, r + r * y1,
                    'L', r + r0 * x1, r + r0 * y1, 'A',
                    r0, r0, 0, largeArc, 0, r + r0 * x0, r + r0 * y0,
                    '" fill="' + color + '" />'].join(' ');
            }

            // filters for classifying earthquakes into five categories based on magnitude
            let mag1 = ["<", ["get", "mag"], 2];
            let mag2 = ["all", [">=", ["get", "mag"], 2], ["<", ["get", "mag"], 3]];
            let mag3 = ["all", [">=", ["get", "mag"], 3], ["<", ["get", "mag"], 4]];
            let mag4 = ["all", [">=", ["get", "mag"], 4], ["<", ["get", "mag"], 5]];
            let mag5 = [">=", ["get", "mag"], 5];

            // colors to use for the categories
            let colors = ['#fed976', '#feb24c', '#fd8d3c', '#fc4e2a', '#e31a1c'];

            // add a clustered GeoJSON source for a sample set of earthquakes
            map.addSource('earthquakes', {
                "type": "geojson",
                "data": `${window.location.origin}/mapbox-test/libs/mapbox/assets/earthquakes.geojson`,
                "cluster": true,
                "clusterRadius": 80,
                "clusterProperties": { // keep separate counts for each magnitude category in a cluster
                    "mag1": ["+", ["case", mag1, 1, 0]],
                    "mag2": ["+", ["case", mag2, 1, 0]],
                    "mag3": ["+", ["case", mag3, 1, 0]],
                    "mag4": ["+", ["case", mag4, 1, 0]],
                    "mag5": ["+", ["case", mag5, 1, 0]]
                }
            });
            // circle and symbol layers for rendering individual earthquakes (unclustered points)
            map.addLayer({
                "id": "earthquake_circle",
                "type": "circle",
                "source": "earthquakes",
                "filter": ["!=", "cluster", true],
                "paint": {
                    "circle-color": ["case",
                        mag1, colors[0],
                        mag2, colors[1],
                        mag3, colors[2],
                        mag4, colors[3], colors[4]],
                    "circle-opacity": 0.6,
                    "circle-radius": 12
                }
            });
            map.addLayer({
                "id": "earthquake_label",
                "type": "symbol",
                "source": "earthquakes",
                "filter": ["!=", "cluster", true],
                "layout": {
                    "text-field": ["number-format", ["get", "mag"], {
                        "min-fraction-digits": 1,
                        "max-fraction-digits": 1
                    }],
                    "text-font": ["Open Sans Semibold", "Arial Unicode MS Bold"],
                    "text-size": 10
                },
                "paint": {
                    "text-color": ["case", ["<", ["get", "mag"], 3], "black", "white"]
                }
            });

            // objects for caching and keeping track of HTML marker objects (for performance)
            let markers = {};
            let markersOnScreen = {};

            const updateMarkers = () => {
                let newMarkers = {};
                let features = map.querySourceFeatures('earthquakes');

                // for every cluster on the screen, create an HTML marker for it (if we didn't yet),
                // and add it to the map if it's not there already
                for (let i = 0; i < features.length; i++) {
                    let coords = features[i].geometry.coordinates;
                    let props = features[i].properties;
                    if (!props.cluster) continue;
                    let id = props.cluster_id;

                    let marker = markers[id];
                    if (!marker) {
                        let el = createDonutChart(props);
                        marker = markers[id] = new mapboxgl.Marker({element: el}).setLngLat(coords);
                    }
                    newMarkers[id] = marker;

                    if (!markersOnScreen[id])
                        marker.addTo(map);
                }
                // for every marker we've added previously, remove those that are no longer visible
                for (let id in markersOnScreen) {
                    if (!newMarkers[id])
                        markersOnScreen[id].remove();
                }
                markersOnScreen = newMarkers;
            }

            // after the GeoJSON data is loaded, update markers on the screen and do so on every map move/moveend
            map.on('data', (e) => {
                if (e.sourceId !== 'earthquakes' || !e.isSourceLoaded) return;

                map.on('move', updateMarkers);
                map.on('moveend', updateMarkers);
                updateMarkers();
            });
        };

        return {
            mapOnLoadCB
        }
    }
}
</script>

<style scoped>

</style>